﻿namespace DiffControl
{
    using Algorithm.Diff;
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Windows.Forms;

    public class DiffView : UserControl
    {
        private ColumnHeader chLeft;
        private ColumnHeader chNumberLeft;
        private ColumnHeader chNumberRight;
        private ColumnHeader chRight;
        private Container components = null;
        private ContextMenu contextMenu1;
        private string fullLeft;
        private string fullRight;
        private IList linesLeft = new string[0];
        private IList linesRight = new string[0];
        private ScrollableListView lvLeft;
        private ScrollableListView lvRight;
        private MenuItem menuItem1;
        private MenuItem menuItem2;
        private Splitter splitter1;

        public event DiffScrollEventHandler ScrollHorizontal;

        public event DiffScrollEventHandler ScrollMouseWheel;

        public event DiffScrollEventHandler ScrollVertical;

        public DiffView()
        {
            this.InitializeComponent();
            this.lvLeft.ScrollVertical += new ScrollEventHandler(this.LeftScrollVertical);
            this.lvRight.ScrollVertical += new ScrollEventHandler(this.RightScrollVertical);
            this.lvLeft.ScrollMouseWheel += new MouseEventHandler(this.LeftScrollMouseWheel);
            this.lvRight.ScrollMouseWheel += new MouseEventHandler(this.RightScrollMouseWheel);
        }

        private void copySelected(ListView lv)
        {
            int num = 0x7fffffff;
            int num2 = -2147483648;
            foreach (ListViewItem item in lv.SelectedItems)
            {
                if (item.Text != "")
                {
                    int num3 = Convert.ToInt32(item.Text);
                    if (num > num3)
                    {
                        num = num3;
                    }
                    if (num2 < num3)
                    {
                        num2 = num3;
                    }
                }
            }
            if ((num != 0x7fffffff) && (num2 != -2147483648))
            {
                num--;
                num2--;
                StringBuilder builder = new StringBuilder((num2 - num) + 1);
                if (this.contextMenu1.SourceControl == this.lvLeft)
                {
                    for (int i = num; i <= num2; i++)
                    {
                        builder.Append((string) this.linesLeft[i]);
                        builder.Append("\r\n");
                    }
                }
                else
                {
                    for (int j = num; j <= num2; j++)
                    {
                        builder.Append((string) this.linesRight[j]);
                        builder.Append("\r\n");
                    }
                }
                Clipboard.SetDataObject(builder.ToString());
            }
        }

        private void DiffView_SizeChanged(object sender, EventArgs e)
        {
            this.splitter1.SplitPosition = base.Size.Width / 2;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (this.components != null))
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }

        public void Init(IList linesLeft, IList linesRight)
        {
            this.linesLeft = linesLeft;
            this.linesRight = linesRight;
            this.lvLeft.Items.Clear();
            this.lvRight.Items.Clear();
            Algorithm.Diff.Diff diff = new Algorithm.Diff.Diff(linesLeft, linesRight, null, null);
            MemoryStream stream = new MemoryStream();
            StringWriter writer = new StringWriter();
            diff.WriteUnifiedDiff(writer);
            int lineCount = 0;
            int num2 = 0;
            foreach (Algorithm.Diff.Diff.Hunk hunk in (IEnumerable) diff)
            {
                if (hunk.Same)
                {
                    this.WriteBlock(ref lineCount, this.lvLeft, hunk.Left);
                    this.WriteBlock(ref num2, this.lvRight, hunk.Left);
                }
                else
                {
                    int fillUp = (hunk.Left.Count > hunk.Right.Count) ? hunk.Left.Count : hunk.Right.Count;
                    this.WriteBlock(ref lineCount, this.lvLeft, hunk.Left, fillUp, DiffType.Left);
                    this.WriteBlock(ref num2, this.lvRight, hunk.Right, fillUp, DiffType.Right);
                }
            }
        }

        public void Init(string leftText, string rightText)
        {
            this.fullLeft = leftText;
            this.fullRight = rightText;
            leftText = leftText.Replace("\r", "");
            rightText = rightText.Replace("\r", "");
            IList linesLeft = leftText.Split(new char[] { '\n' });
            IList linesRight = rightText.Split(new char[] { '\n' });
            this.Init(linesLeft, linesRight);
        }

        public void Init(string leftFileName, string rightFileName, bool readFromFiles)
        {
            IList linesLeft = this.LoadFileLines(leftFileName);
            IList linesRight = this.LoadFileLines(rightFileName);
            this.fullLeft = string.Join("\r\n", (string[]) linesLeft);
            this.fullRight = string.Join("\r\n", (string[]) linesRight);
            this.Init(linesLeft, linesRight);
        }

        private void InitializeComponent()
        {
            this.lvLeft = new ScrollableListView();
            this.chNumberLeft = new ColumnHeader();
            this.chLeft = new ColumnHeader();
            this.splitter1 = new Splitter();
            this.lvRight = new ScrollableListView();
            this.chNumberRight = new ColumnHeader();
            this.chRight = new ColumnHeader();
            this.contextMenu1 = new ContextMenu();
            this.menuItem1 = new MenuItem();
            this.menuItem2 = new MenuItem();
            base.SuspendLayout();
            this.lvLeft.Columns.AddRange(new ColumnHeader[] { this.chNumberLeft, this.chLeft });
            this.lvLeft.Dock = DockStyle.Left;
            this.lvLeft.FullRowSelect = true;
            this.lvLeft.HeaderStyle = ColumnHeaderStyle.None;
            this.lvLeft.HideSelection = false;
            this.lvLeft.Location = new Point(0, 0);
            this.lvLeft.Name = "lvLeft";
            this.lvLeft.Size = new Size(0x91, 0x131);
            this.lvLeft.TabIndex = 0;
            this.lvLeft.View = View.Details;
            this.lvLeft.KeyDown += new KeyEventHandler(this.lv_KeyDown);
            this.lvLeft.MouseDown += new MouseEventHandler(this.lvLeft_MouseDown);
            this.lvLeft.SelectedIndexChanged += new EventHandler(this.lvLeft_SelectedIndexChanged);
            this.chNumberLeft.Text = "Line";
            this.chNumberLeft.TextAlign = HorizontalAlignment.Right;
            this.chNumberLeft.Width = 50;
            this.chLeft.Text = "Left";
            this.chLeft.Width = 0x3e8;
            this.splitter1.Location = new Point(0x91, 0);
            this.splitter1.Name = "splitter1";
            this.splitter1.Size = new Size(3, 0x131);
            this.splitter1.TabIndex = 1;
            this.splitter1.TabStop = false;
            this.lvRight.Columns.AddRange(new ColumnHeader[] { this.chNumberRight, this.chRight });
            this.lvRight.Dock = DockStyle.Fill;
            this.lvRight.FullRowSelect = true;
            this.lvRight.HeaderStyle = ColumnHeaderStyle.None;
            this.lvRight.HideSelection = false;
            this.lvRight.Location = new Point(0x94, 0);
            this.lvRight.Name = "lvRight";
            this.lvRight.Size = new Size(0x115, 0x131);
            this.lvRight.TabIndex = 2;
            this.lvRight.View = View.Details;
            this.lvRight.KeyDown += new KeyEventHandler(this.lv_KeyDown);
            this.lvRight.MouseDown += new MouseEventHandler(this.lvRight_MouseDown);
            this.lvRight.SelectedIndexChanged += new EventHandler(this.lvRight_SelectedIndexChanged);
            this.chNumberRight.Text = "Line";
            this.chNumberRight.TextAlign = HorizontalAlignment.Right;
            this.chNumberRight.Width = 50;
            this.chRight.Text = "Right";
            this.chRight.Width = 0x3e8;
            this.contextMenu1.MenuItems.AddRange(new MenuItem[] { this.menuItem1, this.menuItem2 });
            this.menuItem1.Index = 0;
            this.menuItem1.Text = "Copy";
            this.menuItem1.Click += new EventHandler(this.menuItem1_Click);
            this.menuItem2.Index = 1;
            this.menuItem2.Text = "Copy All";
            this.menuItem2.Click += new EventHandler(this.menuItem2_Click);
            base.Controls.Add(this.lvRight);
            base.Controls.Add(this.splitter1);
            base.Controls.Add(this.lvLeft);
            base.Name = "DiffView";
            base.Size = new Size(0x1a9, 0x131);
            base.SizeChanged += new EventHandler(this.DiffView_SizeChanged);
            base.ResumeLayout(false);
        }

        private void LeftScrollHorizontal(object sender, ScrollEventArgs e)
        {
            this.lvRight.performScrollHorizontal(e.Type);
            if (this.ScrollHorizontal != null)
            {
                this.ScrollHorizontal(sender, new DiffScrollEventArgs(e.Type, e.NewValue, DiffSide.Left));
            }
        }

        private void LeftScrollMouseWheel(object sender, MouseEventArgs e)
        {
            int num = Convert.ToInt32((int) (e.Delta / 40));
            if (e.Delta >= 0)
            {
                for (int i = 0; i < num; i++)
                {
                    this.lvRight.performScrollVertical(ScrollEventType.SmallDecrement);
                }
            }
            else
            {
                for (int j = 0; j > num; j--)
                {
                    this.lvRight.performScrollVertical(ScrollEventType.SmallIncrement);
                }
            }
        }

        private void LeftScrollVertical(object sender, ScrollEventArgs e)
        {
            this.lvRight.performScrollVertical(e.Type);
            if (this.ScrollVertical != null)
            {
                this.ScrollVertical(sender, new DiffScrollEventArgs(e.Type, e.NewValue, DiffSide.Left));
            }
        }

        private string[] LoadFileLines(string file)
        {
            ArrayList list = new ArrayList();
            using (StreamReader reader = new StreamReader(file))
            {
                string str;
                while ((str = reader.ReadLine()) != null)
                {
                    list.Add(str);
                }
            }
            return (string[]) list.ToArray(typeof(string));
        }

        private void lv_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyCode == Keys.C) && e.Control)
            {
                ListView lv = (ListView) sender;
                this.copySelected(lv);
            }
        }

        private void lvLeft_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                this.contextMenu1.Show(this.lvLeft, new Point(e.X, e.Y));
            }
        }

        private void lvLeft_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.lvLeft.SelectedIndices.Count > 0)
            {
                int index = this.lvLeft.SelectedIndices[0];
                this.lvRight.Items[index].Selected = true;
                this.lvRight.EnsureVisible(index);
            }
            else
            {
                foreach (ListViewItem item in this.lvRight.SelectedItems)
                {
                    item.Selected = false;
                }
            }
        }

        private void lvRight_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                this.contextMenu1.Show(this.lvRight, new Point(e.X, e.Y));
            }
        }

        private void lvRight_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.lvRight.SelectedIndices.Count > 0)
            {
                int index = this.lvRight.SelectedIndices[0];
                this.lvLeft.Items[index].Selected = true;
                this.lvLeft.EnsureVisible(index);
            }
            else
            {
                foreach (ListViewItem item in this.lvLeft.SelectedItems)
                {
                    item.Selected = false;
                }
            }
        }

        private void menuItem1_Click(object sender, EventArgs e)
        {
            ListView sourceControl = (ListView) this.contextMenu1.SourceControl;
            this.copySelected(sourceControl);
        }

        private void menuItem2_Click(object sender, EventArgs e)
        {
            if (this.contextMenu1.SourceControl == this.lvLeft)
            {
                Clipboard.SetDataObject(this.fullLeft);
            }
            else if (this.contextMenu1.SourceControl == this.lvRight)
            {
                Clipboard.SetDataObject(this.fullRight);
            }
        }

        private void RightScrollHorizontal(object sender, ScrollEventArgs e)
        {
            this.lvLeft.performScrollHorizontal(e.Type);
            if (this.ScrollHorizontal != null)
            {
                this.ScrollHorizontal(sender, new DiffScrollEventArgs(e.Type, e.NewValue, DiffSide.Right));
            }
        }

        private void RightScrollMouseWheel(object sender, MouseEventArgs e)
        {
            int num = Convert.ToInt32((int) (e.Delta / 40));
            if (e.Delta >= 0)
            {
                for (int i = 0; i < num; i++)
                {
                    this.lvLeft.performScrollVertical(ScrollEventType.SmallDecrement);
                }
            }
            else
            {
                for (int j = 0; j > num; j--)
                {
                    this.lvLeft.performScrollVertical(ScrollEventType.SmallIncrement);
                }
            }
        }

        private void RightScrollVertical(object sender, ScrollEventArgs e)
        {
            this.lvLeft.performScrollVertical(e.Type);
            if (this.ScrollVertical != null)
            {
                this.ScrollVertical(sender, new DiffScrollEventArgs(e.Type, e.NewValue, DiffSide.Right));
            }
        }

        private void WriteBlock(ref int lineCount, ListView lv, Algorithm.Diff.Range range)
        {
            this.WriteBlock(ref lineCount, lv, range, 0, DiffType.Same);
        }

        private void WriteBlock(ref int lineCount, ListView lv, Algorithm.Diff.Range range, int fillUp, DiffType type)
        {
            Font font;
            int num = 0;
            switch (type)
            {
                case DiffType.Left:
                case DiffType.Right:
                    font = new Font(lv.Font, FontStyle.Bold);
                    break;

                default:
                    font = new Font(lv.Font, FontStyle.Regular);
                    break;
            }
            foreach (object obj2 in (IEnumerable) range)
            {
                string text = obj2.ToString().Replace("\t", "    ");
                lineCount++;
                ListViewItem item = lv.Items.Add(((int) lineCount).ToString());
                item.UseItemStyleForSubItems = true;
                item.SubItems.Add(text);
                if (type == DiffType.Left)
                {
                    item.BackColor = Color.LightGoldenrodYellow;
                    item.ForeColor = Color.Red;
                    item.Font = font;
                }
                else if (type == DiffType.Right)
                {
                    item.BackColor = Color.LightGoldenrodYellow;
                    item.ForeColor = Color.DarkGreen;
                    item.Font = font;
                }
                num++;
            }
            while (num < fillUp)
            {
                lv.Items.Add("").BackColor = Color.LightGoldenrodYellow;
                num++;
            }
        }

        public delegate void DiffScrollEventHandler(object sender, DiffScrollEventArgs e);

        private enum DiffType
        {
            Same,
            Left,
            Right
        }
    }
}

